#include "protocol.hpp"
#include <queue>
#include <pthread.h>
template <class T>
class Thread_pool;
template <class T>
struct thread_data
{
    thread_data(T& data,Thread_pool<T> *const ptr)
        : _ptr(ptr)
        ,_request(data)
    {
    }
    T _data;
    T& _request;
    Thread_pool<T> *_ptr;
};
template <class T>
class Thread_pool
{
public:
    Thread_pool()
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_full, nullptr);
        pthread_cond_init(&_empty, nullptr);
        for (int i = 0; i < PID_NUM; i++)
            _pid[i] = 0;
    }
    void Start(const T &data, T &request) 
    {
        push(data);
        for (int i = 0; i < PID_NUM; i++)
        {
            if (_pid[i] == 0)
            {
                thread_data<T> *ptr = new thread_data<T>(request,this);
                pthread_create(_pid + i, nullptr, Work, ptr);
                _map.emplace(std::make_pair(_pid[i], ptr));
            }
            else
                continue;
        }
    }

private:
    static void *Work(void *args)
    {
        pthread_detach(pthread_self());
        thread_data<T> *ptr = reinterpret_cast<thread_data<T> *>(args);
        while (true)
        {
            ptr->_ptr->pop(ptr->_data);
            //处理数据
            //返回请求
            

        }
        return nullptr;
    }
    void push(const T &data)
    {
        pthread_mutex_lock(&_mtx);
        while (_task_list.size() == 5)
            pthread_cond_wait(&_full, &_mtx);
        _task_list.push(data);
        cout << pthread_self() << ":" << endl;
        pthread_mutex_unlock(&_mtx);
        pthread_cond_signal(&_empty);
    }
    void pop(T &data)
    {
        pthread_mutex_lock(&_mtx);
        while (_task_list.size() == 0)
            pthread_cond_wait(&_empty, &_mtx);
        data = _task_list.front();
        _task_list.pop();
        cout << pthread_self() << ":" << endl;
        pthread_mutex_unlock(&_mtx);
        pthread_cond_signal(&_full);
    }

public:
    ~Thread_pool()
    {
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_full);
        pthread_cond_destroy(&_empty);
        for (auto &e : _map)
        {
            if (e.second)
                delete e.second;
        }
    }

private:
    pthread_t _pid[PID_NUM];
    pthread_mutex_t _mtx;
    pthread_cond_t _full;
    pthread_cond_t _empty;
    std::queue<T> _task_list;
    std::unordered_map<pthread_t, thread_data<T> *> _map;
};